from django.db.models import Q
from django.http import JsonResponse

from AI.knowledgeRetriever import agents
from .models import Jobposting  # 请根据实际模型导入路径修改

from tools.tool_hot import recommended_products
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from home import models, homeser
from user import models as um, userser

from utils.myRedis import myRedis
from tools.tool_lock import RedisDistributedLock
import json
import logging
from rest_framework.permissions import AllowAny

# 日志
logger = logging.getLogger(__name__)


class JobCategoriesAPIView(APIView):
    permission_classes = [AllowAny]

    def get(self, request, *args, **kwargs):
        print("获取所有一级分类")
        # 获取所有根分类（pid为None的项）
        root_categories = models.JobCategories.objects.filter(
            pid__isnull=True
        ).prefetch_related(
            'children__children'  # 预取二级和三级分类
        )

        serializer = homeser.JobCategoriesSerializerYi(
            root_categories,
            many=True,
            context={'request': request}
        )

        return Response(serializer.data, status=status.HTTP_200_OK)


# 获取所有一级分类展示--嵌套展示二级三级及招聘信息  详情页列表按热度排序
class JobCateOne(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        """获取所有一级分类"""
        # 获取所有一级分类111
        jobcates = models.JobCategories.objects.filter(pid=None)
        # 序列化一级分类（自动嵌套二级、三级分类）
        serializer = homeser.RecursiveJobCategoriesSer(jobcates, many=True)
        return Response({
            "code": 200,
            "data": serializer.data,
            "msg": "分类树加载成功"
        })


# 根据一级分类展示所有招聘信息
class JobCateList(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        jobcate_id = request.GET.get('jobcate_id')
        logger.info(f"前端传分类id 65:{jobcate_id}")
        if not jobcate_id:
            return Response({'code': 400, 'error': '请选择职位分类'})

        cache_key = f"hot_jobs:{jobcate_id}"
        # 1. 读取缓存
        cacha_data = myRedis.get(cache_key)

        logger.info(f"缓存数据: {cacha_data}")
        if cacha_data:
            try:
                deserialized_data = json.loads(cacha_data)
                # 验证缓存数据有效性
                if deserialized_data:
                    return Response({
                        'code': 200,
                        'data': deserialized_data,  # 直接使用缓存的序列化数据
                        'msg': "该行业招聘信息加载成功（缓存）"
                    })
                else:
                    logger.warning(f"缓存数据为空: {cache_key}")
                    myRedis.delete(cache_key)  # 删除空缓存
            except json.JSONDecodeError as e:
                logger.error(f"缓存反序列化失败: {cache_key}, 错误: {e}")
                myRedis.delete(cache_key)  # 删除损坏的缓存

        # 2. 加锁处理
        lock = RedisDistributedLock(
            redis_client=myRedis,
            lock_prefix="lock:hot_jobs",
            category_id=jobcate_id,
            retry_count=3,
            retry_delay=0.1,
            lock_timeout=10
        )
        lock_response = lock.handle_lock()
        if lock_response:
            return lock_response

        # 3. 缓存未命中，执行数据库查询
        try:
            # 查询职位分类
            jobcates = models.JobCategories.objects.filter(pid=jobcate_id)
            logger.info(f"职位分类: {jobcates}")
            if not jobcates.exists():
                return Response({'code': 400, 'error': '该分类下暂无职位信息'})

            # 获取三级分类
            three_cates = []
            for job in jobcates:
                logger.info(f"115-数据:{list(job.children.all())}")
                three_cates.extend(list(job.children.all()))
            if not three_cates:
                return Response({'code': 400, 'error': '该分类下暂无职位信息'})

            three_ids = [three_cate.id for three_cate in three_cates]
            jobpostings = models.Jobposting.objects.filter(jobcate__in=three_ids)
            # print(jobpostings)
            logger.info(f"122-数据: {jobpostings}")

            # 检查是否有职位数据
            if not jobpostings.exists():
                return Response({'code': 400, 'error': '该分类下暂无招聘信息'})

            jobposting_ids = jobpostings.values_list('id', flat=True)
            logger.info(f"130-数据:{jobposting_ids}")

            # 返回热门职位id列表
            hot_jobpostings = recommended_products(jobposting_ids)
            logger.info(f"134-数据:{hot_jobpostings}")
            # 验证计算结果
            if not hot_jobpostings:
                return Response({
                    'code': 200,
                    'data': [],
                    'msg': "该分类下暂无热门职位（无浏览/收藏数据）"
                })

            # 1. 提取排序后的 ID 列表和热度映射
            sorted_ids = [job['jobposting_id'] for job in hot_jobpostings]
            score_mapping = {job['jobposting_id']: job['hot_score'] for job in hot_jobpostings}

            # 2. 查询完整数据（使用 sorted_ids 保持顺序）
            hot_jobposting = models.Jobposting.objects.filter(id__in=sorted_ids)

            # 3. 按工具类的排序顺序重新排列查询集
            #    将查询集转换为列表，并用 sorted_ids 的顺序排序
            hot_jobposting_list = list(hot_jobposting)
            hot_jobposting_list.sort(key=lambda x: sorted_ids.index(x.id))

            # 使用序列化器处理数据
            serializer = homeser.JobpostingSer(hot_jobposting_list, many=True)
            serialized_data = serializer.data

            # 缓存序列化后的数据
            cache_data = json.dumps(serialized_data)
            myRedis.set(cache_key, cache_data, 3600)

            return Response({
                'code': 200,
                'data': serialized_data,
                'msg': "该行业招聘信息加载成功（数据库）"
            })

        except Exception as e:
            logger.error(f"获取热门职位失败: {e}", exc_info=True)
            return Response({"code": 500, 'error': '服务器内部错误，请稍后重试'})
        finally:
            # 确保锁始终释放
            if lock:
                lock.release_lock()


from user.models import Company


class CompanyList(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        lists = Company.objects.all()
        serializer = userser.CompanySerializer(lists, many=True)
        return Response({"code": 200, "msg": "获取成功", "data": serializer.data})


class JobList(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        keyword = request.query_params.get("keyword", None)
        city = request.query_params.get("city", None)
        type = request.query_params.get("type", None)
        working = request.query_params.get("working", None)
        education = request.query_params.get("education", None)
        query = Q()
        if keyword:
            query &= (
                    Q(title__icontains=keyword) |
                    Q(description__icontains=keyword) |
                    Q(company__name__icontains=keyword)
            )
        if city:
            query &= Q(city__name__icontains=city)
        if type:
            query = query & Q(type=type)
        if working:
            query = query & Q(working=working)
        if education:
            query = query & Q(education=education)
        queryset = Jobposting.objects.filter(query)
        serializer = homeser.JobpostingSer(queryset, many=True)
        return Response({"code": 200, "msg": "获取成功", "data": serializer.data})


# 热门公司中的热门职位
class HotJobView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        # 尝试从缓存获取热门公司数据
        hot_company_data = myRedis.get('hot_company_data')

        if hot_company_data:
            logger.info("进入到缓存中")
            try:
                deserialized_data = json.loads(hot_company_data)
                # 验证缓存数据有效性
                if deserialized_data:
                    return Response({
                        'code': 200,
                        'data': deserialized_data,  # 直接使用缓存的序列化数据
                        'msg': "该行业招聘信息加载成功（缓存）"
                    })
                else:
                    logger.warning(f"缓存数据为空: {hot_company_data}")
                    myRedis.delete(hot_company_data)  # 删除空缓存
            except json.JSONDecodeError as e:
                logger.error(f"缓存反序列化失败: {hot_company_data}, 错误: {e}")
                myRedis.delete(hot_company_data)  # 删除损坏的缓存

        # if hot_company_data:
        #     # 缓存命中，直接返回
        #     return Response({"code": 200, "msg": "获取成功", "data": json.loads(hot_company_data)})
        else:
            company_list = um.Company.objects.all()
            score = {i.id: i.collect_number * 0.5 + i.browse_number * 0.5 for i in company_list}
            # 将分数倒叙排序取出前9条数据
            company_list = sorted(score, key=lambda x: score[x], reverse=True)[:9]
            company_list = [um.Company.objects.get(id=i) for i in company_list]
            ser = userser.CompanySerializer(company_list, many=True)

            # 获取每一个热门公司中3条热门职位信息
            data = ser.data
            for i in data:
                job = models.Jobposting.objects.filter(company_id=i["id"])
                score = {j.id: j.collect_number * 0.3 + j.browse_number * 0.3 + j.deliver_number * 0.4 for j in job}
                hot_jobs = [j for j in sorted(score, key=score.get, reverse=True)[:3]]
                job_serializer = homeser.JobInfoSerializer(models.Jobposting.objects.filter(id__in=hot_jobs),
                                                           many=True)
                i['job_list'] = job_serializer.data  # 获取序列化后的数据

            myRedis.set("hot_company_data", json.dumps(data))

            return Response({"code": 200, "msg": "获取成功", "data": json.loads(myRedis.get("hot_company_data"))})


# 获取城市列表
class CityListView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        # 获取pid不为空的城市
        citys = um.City.objects.filter(pid__gte=1)

        ser = userser.CitySerializer(citys, many=True)
        return Response({"code": 200, "msg": "成功", "data": ser.data})


# 获取行业二级标题列表
class JobCategoriesListView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        job_categories = models.JobCategories.objects.filter(pid=None)
        job_list = models.JobCategories.objects.filter(pid__in=job_categories)
        ser = homeser.JobCategoriesSerializer(job_list, many=True)
        return Response({"code": 200, "msg": "成功", "data": ser.data})


# 公司列表
class CompanyListView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        city = request.query_params.get('city')
        job = request.query_params.get('job')
        finance = request.query_params.get('finance')
        num1 = request.query_params.get('num1')
        num2 = request.query_params.get('num2')
        query = Q()
        if city and city != '0':
            query = query & Q(city=city)

        if job and job != '0':
            job_ids = models.Jobposting.objects.filter(jobcate=job).values_list('company_id', flat=True)
            query = query & Q(id__in=job_ids)

        if finance:
            query = query & Q(is_listed=finance)

        if num1 and num1 != '0':
            query = query & Q(employee_number__gte=num1)

        if num2 and num2 != '0':
            query = query & Q(employee_number__lte=num2)

        company = um.Company.objects.filter(query)
        ser = userser.CompanySerializer(company, many=True)
        return Response({'code': 200, 'msg': '查询成功', 'data': ser.data})


class CompanyDetailView(APIView):
    def get(self, request):
        id = request.query_params.get('id')
        company = um.Company.objects.get(id=id)
        ser = userser.CompanySerializer(company)
        return Response({'code': 200, 'msg': '查询成功', 'data': ser.data})


class Company_JobView(APIView):
    def get(self, request):
        company = request.query_params.get('id')
        job = models.Jobposting.objects.filter(company_id=company)
        ser = homeser.JobpostingSer(job, many=True)
        return Response({'code': 200, 'msg': '查询成功', 'data': ser.data})


# interviews/views.py
from rest_framework import status
from job_tools.moni import InterviewAgent
import asyncio


class InterviewAPI(APIView):
    agent = None

    def __init__(self):
        super().__init__()
        if not InterviewAPI.agent:
            InterviewAPI.agent = InterviewAgent()

    def post(self, request):
        action = request.data.get('action')

        if action == 'start':
            self_intro = request.data.get('self_intro', '')
            if not self_intro:
                return Response({'error': '自我介绍不能为空'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                # 运行异步函数
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
                start_result = loop.run_until_complete(self.agent.start_interview(self_intro))
                loop.close()

                return Response({
                    'status': 'started',
                    'data': start_result,
                    'greeting': f"您好！感谢参加{start_result['position']}职位的模拟面试。",
                    'first_question': start_result['first_question']
                })
            except Exception as e:
                return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        elif action == 'submit_answer':
            answer = request.data.get('answer', '')
            if not answer:
                return Response({'error': '回答不能为空'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
                result = loop.run_until_complete(self.agent.submit_answer(answer))
                loop.close()

                if result['status'] == 'completed':
                    return Response({
                        'status': 'completed',
                        'report': result['report'],
                        'position': result['position']
                    })
                else:
                    return Response({
                        'status': 'next_question',
                        'question': result['question'],
                        'progress': result['progress'],
                        'question_type': result['question_type'],
                        'current_phase': result['current_phase']
                    })
            except Exception as e:
                return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({'error': '无效操作'}, status=status.HTTP_400_BAD_REQUEST)


# 添加会话
class QuestionAnswerAdd(APIView):
    # authentication_classes = [myMiddleware.AuthMiddleware]

    def post(self, request):
        user = request.data.get("user")
        jobinfo = um.JobInfo.objects.filter(user_id=user).first()
        if not jobinfo:
            return Response({'code': 400, 'msg': '未找到该用户的求职信息，无法创建会话'}, status=400)
        questionanswer = models.QuestionAnswer.objects.create(jobinfo=jobinfo, name='未命名')
        ser = homeser.QuestionAnswerSerializer(questionanswer)
        return Response({'code': 200, 'msg': '成功', 'data': ser.data})


# 问答系统
class QuestionAnswerView(APIView):
    # authentication_classes = [myMiddleware.AuthMiddleware]

    def post(self, request):
        # 获取会话的id
        qa = request.data.get("qa")
        # 获取用户的问题
        question = request.data.get('question')
        # 获取答案 调用
        res = agents.answer_question(question)
        question_answer = models.QuestionAnswerInfo.objects.create(questionanswer_id=qa, question=question, answer=res)
        ser = homeser.QuestionAnswerInfoSerializer(question_answer)
        return Response({'code': 200, 'msg': '成功', 'data': ser.data})


# 更改会话名称
class QuestionAnswerUpdate(APIView):
    # authentication_classes = [myMiddleware.AuthMiddleware]

    def post(self, request):
        id = request.data.get("id")
        question = request.data.get("question")
        qa = models.QuestionAnswer.objects.filter(id=id).first()
        qa.name = question
        qa.save()
        ser = homeser.QuestionAnswerSerializer(qa)
        return Response({'code': 200, 'msg': '成功', 'data': ser.data})


# 查看所有会话
class QuestionAnswerAll(APIView):
    # authentication_classes = [myMiddleware.AuthMiddleware]

    def get(self, request):
        user = request.query_params.get("user")
        jobinof = um.JobInfo.objects.filter(user_id=user).first()
        qa = models.QuestionAnswer.objects.filter(jobinfo=jobinof)
        if not qa:
            return Response({'code': 200, 'msg': '成功', 'data': "暂无会话"})
        ser = homeser.QuestionAnswerSerializer(qa, many=True)
        return Response({'code': 200, 'msg': '成功', 'data': ser.data})


# 查询会话下的问答内容
class QuestionAnswerAllInfo(APIView):
    # authentication_classes = [myMiddleware.AuthMiddleware]

    def get(self, request):
        id = request.query_params.get("id")
        qa = models.QuestionAnswer.objects.filter(id=id).first()
        qa_info = models.QuestionAnswerInfo.objects.filter(questionanswer=qa)
        ser = homeser.QuestionAnswerInfoSerializer(qa_info, many=True)
        return Response({'code': 200, 'msg': '成功', 'data': ser.data})


from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
import random


class TestWebsocket(APIView):
    def get(self, request):
        # 获取信息
        # 查询数据库对比

        # update = AllDataConsumersUpdate()
        # update.all_active_visit_data()
        channel_layer = get_channel_layer()
        send_data = {"error": "1号大鹏温度太高", 'namelist': ['1001', '1002'],
                     'valuelist': [random.randint(10, 100), random.randint(100, 200)]}
        # send_data = {"name":rand.randint(1,100)}
        async_to_sync(channel_layer.group_send)(
            '1',  # 房间组名
            {
                'type': 'send_to_chrome',  # 消费者中处理的函数
                'data': send_data
            }
        )
        return JsonResponse({"code": 200, "msg": "更新数据成功"})


class HrandJObView(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        id = request.data.get('id')
        data = um.User.objects.filter(id=id).first()
        res = userser.UserSerializer(data)
        return Response(res.data.get('role'))


from django.http import JsonResponse
from django.views import View
from django.db.models import Q
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from .models import Jobposting
from django.core.paginator import Paginator
import json


@method_decorator(csrf_exempt, name='dispatch')
class JobGlobalSearchView(View):
    """
    职位全字段模糊搜索视图
    支持通过单个关键词搜索Jobposting表所有字段

    请求方式: POST
    请求格式: JSON
    示例请求:
    {
        "keyword": "工程师",
        "page": 1,
        "page_size": 10
    }
    """

    def post(self, request):
        try:
            # 1. 解析请求数据
            try:
                data = json.loads(request.body)
                keyword = data.get('keyword', '').strip()
                page = int(data.get('page', 1))
                page_size = int(data.get('page_size', 10))
            except (json.JSONDecodeError, ValueError) as e:
                return JsonResponse({
                    'status': 'error',
                    'message': '无效的请求数据格式'
                }, status=400)

            # 2. 验证关键词
            if not keyword:
                return JsonResponse({
                    'status': 'error',
                    'message': '搜索关键词不能为空'
                }, status=400)

            # 3. 构建全字段查询条件
            query = Q()

            # 3.1 直接字段查询
            direct_fields = [
                'title', 'money', 'education', 'label', 'description',
                'browse_number', 'collect_number', 'deliver_number'
            ]
            for field in direct_fields:
                query |= Q(**{f"{field}__icontains": keyword})

            # 3.2 处理choices字段的显示值查询
            type_choices = dict(Jobposting._meta.get_field('type').choices)
            working_choices = dict(Jobposting._meta.get_field('working').choices)

            # 搜索type和working的显示值
            for value, display in type_choices.items():
                if keyword in display:
                    query |= Q(type=value)

            for value, display in working_choices.items():
                if keyword in display:
                    query |= Q(working=value)

            # 3.3 关联字段查询
            related_mappings = {
                'city': ['name'],  # 查询城市名称
                'company': ['name'],  # 查询公司名称
                'hr': ['name'],  # 查询HR名称
                'jobcate': ['name']  # 查询职位分类名称
            }

            for field, attrs in related_mappings.items():
                for attr in attrs:
                    query |= Q(**{f"{field}__{attr}__icontains": keyword})

            # 4. 执行查询（预加载关联对象）
            jobs = Jobposting.objects.filter(query) \
                .select_related('city', 'company', 'hr', 'jobcate') \
                .order_by('-collect_number')  # 默认按收藏数降序

            # 5. 分页处理
            paginator = Paginator(jobs, page_size)
            page_obj = paginator.get_page(page)

            # 6. 构造响应数据
            results = []
            for job in page_obj:
                results.append({
                    'id': job.id,
                    'title': job.title,
                    'money': job.money,
                    'type': job.get_type_display(),
                    'working': job.get_working_display(),
                    'education': job.education,
                    'label': job.label,
                    'description': job.description[:200] + '...' if len(job.description) > 200 else job.description,
                    'city': job.city.name if job.city else None,
                    'company': {
                        'id': job.company.id,
                        'name': job.company.name,
                        'logo': job.company.logo
                    },
                    'hr': job.hr.name if job.hr else None,
                    'job_category': job.jobcate.name if job.jobcate else None,
                    'stats': {
                        'browse': job.browse_number,
                        'collect': job.collect_number,
                        'deliver': job.deliver_number
                    }
                })

            return JsonResponse({
                'status': 'success',
                'total_count': paginator.count,
                'total_pages': paginator.num_pages,
                'current_page': page_obj.number,
                'data': results
            })

        except Exception as e:
            return JsonResponse({
                'status': 'error',
                'message': f'服务器错误: {str(e)}'
            }, status=500)
